package com.xiaoyushu.xiaoyushu.auth.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.google.common.base.Preconditions;
import com.xiaoyushu.framework.common.exception.BizException;
import com.xiaoyushu.framework.common.response.Response;
import com.xiaoyushu.user.dto.resp.FindUserByPhoneRspDTO;
import com.xiaoyushu.xiaoyushu.auth.constant.RedisKeyConstants;
import com.xiaoyushu.xiaoyushu.auth.enums.LoginTypeEnum;
import com.xiaoyushu.xiaoyushu.auth.enums.ResponseCodeEnum;
import com.xiaoyushu.xiaoyushu.auth.filter.LoginUserContextHolder;
import com.xiaoyushu.xiaoyushu.auth.model.vo.user.UpdatePasswordReqVO;
import com.xiaoyushu.xiaoyushu.auth.model.vo.user.UserLoginReqVO;
import com.xiaoyushu.xiaoyushu.auth.rpc.UserRpcService;
import com.xiaoyushu.xiaoyushu.auth.service.AuthService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Objects;

@Service
@Slf4j
public class UserServiceImpl implements AuthService {


    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserRpcService userRpcService;
    /**
     * 修改密码
     * @param updatePasswordReqVO
     * @return
     */
    @Override
    public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
        String newPassword = updatePasswordReqVO.getNewPassword(); //新密码
        String encodePassword = passwordEncoder.encode(newPassword);//密码加密
        //获取当前请求对应的用户ID
        Long userId = LoginUserContextHolder.getUserId();
        //更新密码
        //   userDOMapper.updateByPrimaryKeySelective(userDo);
//RPC：调用用户服务，更新密码
        userRpcService.updatePassword(encodePassword);
        return Response.success();
    }
    /**
     * 登录与注册
     * @param userLoginReqVO
     * @return
     */
    @Override
    public Response<String> loginAndRegister(UserLoginReqVO userLoginReqVO) {
        String phone = userLoginReqVO.getPhone();
        Integer type = userLoginReqVO.getType();

        LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(type);

        //登录类型错误
        if (Objects.isNull(loginTypeEnum)){
            throw new BizException(ResponseCodeEnum.LOGIN_TYPE_ERROR);
        }

        Long userId = null;

        // 判断登录类型
        switch (loginTypeEnum) {
            case VERIFICATION_CODE: // 验证码登录
                String verificationCode = userLoginReqVO.getCode();

                // 校验入参验证码是否为空
             /*   if (StringUtils.isBlank(verificationCode)) {
                    return Response.fail(ResponseCodeEnum.PARAM_NOT_VALID.getErrorCode(), "验证码不能为空");
                }*/
                // 校验入参验证码是否为空
                Preconditions.checkArgument(StringUtils.isNotBlank(verificationCode), "验证码不能为空");

                // 构建验证码 Redis Key
                String key = RedisKeyConstants.buildVerificationCodeKey(phone);
                // 查询存储在 Redis 中该用户的登录验证码
                String sentCode = (String) redisTemplate.opsForValue().get(key);

                // 判断用户提交的验证码，与 Redis 中的验证码是否一致
                if (!StringUtils.equals(verificationCode, sentCode)) {
                    throw new BizException(ResponseCodeEnum.VERIFICATION_CODE_ERROR);
                }

                //RPC ：调用用户服务，注册用户
                Long userIdTmp = userRpcService.register(phone);
                //若调用用户服务，返回的用户ID为空，则提示登录失败
                if (Objects.isNull(userIdTmp)){
                    throw new BizException(ResponseCodeEnum.LOGIN_FAIL);
                }
                userId = userIdTmp;
                break;
            case PASSWORD: // 密码登录
                //
                String password = userLoginReqVO.getPassword();

                //RPC： 调用用户服务，通过手机号查询用户
                FindUserByPhoneRspDTO userByPhoneRspDTO = userRpcService.findUserByPhoneRspDTO(phone);
                //判断手机号是否注册
                if (Objects.isNull(userByPhoneRspDTO)){
                    throw new BizException(ResponseCodeEnum.USER_NOT_FOUND);
                }
                //拿到密文密码
                String encodePassword = userByPhoneRspDTO.getPassword();


                // 判断 该手机号是否一致
               boolean isPasswordCorrect= passwordEncoder.matches(password,encodePassword);

               //如果不正确，则抛出业务异常，提示用户名或者密码不正确
                if (!isPasswordCorrect){
                    throw new BizException(ResponseCodeEnum.PHONE_OR_PASSWORD_ERROR);
                }
                userId=userByPhoneRspDTO.getId();
                break;
            default:
                break;
        }

        // SaToken 登录用户， 入参是用户ID 并返回 token 令牌
        StpUtil.login(userId);

        //获取Token 令牌
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

        //返回Token 令牌
        return Response.success(tokenInfo.tokenValue);
    }
   /*
    @Autowired
    UserRoleDOMapper userRoleDOMapper;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private RoleDOMapper roleDOMapper;
    */
    /**
     * 系统自动注册用户
     * @param phone
     * @return
     */
    /*
    @Transactional(rollbackFor = Exception.class)
    public Long registerUser(String phone) {
        return transactionTemplate.execute(status -> {
            try {
                // 获取全局自增的小哈书 ID
                Long xiaohashuId = redisTemplate.opsForValue().increment(RedisKeyConstants.XIAOYUSHU_ID_GENERATOR_KEY);

                UserDO userDO = UserDO.builder()
                        .phone(phone)
                        .xiaohashuId(String.valueOf(xiaohashuId)) // 自动生成小红书号 ID
                        .nickname("小红薯" + xiaohashuId) // 自动生成昵称, 如：小红薯10000
                        .status(StatusEnum.ENABLE.getValue()) // 状态为启用
                        //.createTime(LocalDateTime.now())
                        .createTime(new Date())
                        .updateTime(new Date())
                        .isDeleted(DeletedEnum.NO.getValue()) // 逻辑删除
                        .build();

                // 添加入库
                userDOMapper.insert(userDO);

                // 获取刚刚添加入库的用户 ID
                Long userId = userDO.getId();

                // 给该用户分配一个默认角色
                UserRoleDO userRoleDO = UserRoleDO.builder()
                        .userId(userId)
                        .roleId(RoleConstants.COMMON_USER_ROLE_ID)
                        .createTime(new Date())
                        .updateTime(new Date())
                        .isDeleted(DeletedEnum.NO.getValue())
                        .build();
                userRoleDOMapper.insert(userRoleDO);

                // 将该用户的角色 ID 存入 Redis 中
*/
    /*
                List<Long> roles = Lists.newArrayList();
                roles.add(RoleConstants.COMMON_USER_ROLE_ID);

                String userRolesKey = RedisKeyConstants.buildUserRoleKey(phone);
                redisTemplate.opsForValue().set(userRolesKey, JsonUtils.toJsonString(roles));*/
    /*
                RoleDO roleDO = roleDOMapper.selectByPrimaryKey(RoleConstants.COMMON_USER_ROLE_ID);


                // 将该用户的角色 ID 存入 Redis 中，指定初始容量为 1，这样可以减少在扩容时的性能开销
                List<String> roles = new ArrayList<>(1);
                roles.add(roleDO.getRoleKey());

                String userRolesKey = RedisKeyConstants.buildUserRoleKey(userId);
                redisTemplate.opsForValue().set(userRolesKey, JsonUtils.toJsonString(roles));

                return userId;
            }catch (Exception e){
                status.setRollbackOnly();//标记事务为回滚
                log.error("==>系统注册用户异常：",e);
                return null;
            }
        });

    }*/
    /**
     * 退出登录
     * @param userId
     * @return
     */
    @Override
    public Response<?> logout(Long userId) {
        // 退出登录 (指定用户 ID)
        StpUtil.logout(userId);

        return Response.success();
    }
    @Resource(name = "taskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    /**
     * 注册用户
     * @return
     */
    @Override
    public Response<?> logout() {
        //调用接口的时候，过滤器拿到用户的id放入线程中，然后，直接调用
        Long userId = LoginUserContextHolder.getUserId();
        log.info("---> 用户退出登录，userId：{}",userId);
        log.info(
                "==>异步线程中获取 用户退出登录, userId: {}",
                userId
        );
        threadPoolTaskExecutor.submit(() -> {
           Long userId2= LoginUserContextHolder.getUserId();
           log.info("==>异步线程中获取 用户退出登录, userId: {}",userId2);
        });

        //退出登录（指定用户id）
        StpUtil.logout(userId);
        return Response.success();
    }


}